#!/usr/bin/env python
__license__ = 'GPL v3'

import json
from datetime import datetime
from urllib.parse import urljoin

from calibre.web.feeds.news import BasicNewsRecipe, prefixed_classes


class ScientificAmerican(BasicNewsRecipe):
    title = 'Scientific American'
    description = 'Popular Science. Monthly magazine. Should be downloaded around the middle of each month.'
    category = 'science'
    __author__ = 'Kovid Goyal'
    no_stylesheets = True
    language = 'en'
    publisher = 'Nature Publishing Group'
    remove_empty_feeds = True
    remove_javascript = True
    timefmt = ' [%B %Y]'
    remove_attributes = ['height', 'width']
    masthead_url = (
        'https://static.scientificamerican.com/sciam/assets/Image/newsletter/salogo.png'
    )
    extra_css = '''
        [class^="article_dek-"] { font-style:italic; color:#202020; }
        [class^="article_authors-"] {font-size:small; color:#202020; }
        [class^="article__image-"], [class^="lead_image-"], .calibre-nuked-tag-figcaption { font-size:small; }
        [class^="bio-"] { font-size:small; color:#404040; }
        em, blockquote { color:#202020; }
    '''

    needs_subscription = 'optional'

    keep_only_tags = [
        prefixed_classes(
            'article_hed- article_dek- article_authors- lead_image- article__body- bio-'
        ),
    ]
    remove_tags = [
        dict(name=['button', 'svg', 'iframe', 'source'])
    ]

    def preprocess_html(self, soup):
        for h2 in soup.findAll(['h2', 'h3']):
            h2.name = 'h4'
        for fig in soup.findAll('figcaption'):
            for p in fig.findAll('p'):
                p.name = 'div'
        res = '?w=600'
        w = self.recipe_specific_options.get('res')
        if w and isinstance(w, str):
            res = '?w=' + w
        for img in soup.findAll('img', src=True):
            img['src'] = img['src'].split('?')[0] + res
        return soup

    def get_browser(self, *args):
        br = BasicNewsRecipe.get_browser(self)
        if self.username and self.password:
            br.open('https://www.scientificamerican.com/account/login/')
            br.select_form(predicate=lambda f: f.attrs.get('id') == 'login')
            br['emailAddress'] = self.username
            br['password'] = self.password
            br.submit()
        return br

    recipe_specific_options = {
        'issue_url': {
            'short': 'The issue URL ',
            'long': (
                'For example, https://www.scientificamerican.com/issue/sa/2024/07-01/'
                '\nYou can also download special-editions, physics, health, mind magazines by pasting the URL here.'
            )
        },
        'res': {
            'short': 'For hi-res images, select a resolution from the\nfollowing options: 800, 1000, 1200 or 1500',
            'long': 'This is useful for non e-ink devices, and for a lower file size\nthan the default, use 400 or 300.',
            'default': '600'
        }
    }

    def parse_index(self):
        # Get the cover, date and issue URL
        d = self.recipe_specific_options.get('issue_url')
        if d and isinstance(d, str):
            issue = d
        else:
            fp_soup = self.index_to_soup('https://www.scientificamerican.com')
            curr_issue_link = fp_soup.find(**prefixed_classes('latest_issue_links-'))
            if not curr_issue_link:
                self.abort_recipe_processing('Unable to find issue link')
            issue = 'https://www.scientificamerican.com' + curr_issue_link.a['href']

        soup = self.index_to_soup(issue)
        script = soup.find('script', id='__DATA__')
        if not script:
            self.abort_recipe_processing('Unable to find script')

        JSON = script.contents[0].split('JSON.parse(`')[1].replace('\\\\', '\\')
        data = json.JSONDecoder().raw_decode(JSON)[0]
        issue_info = (
            data
            .get('initialData', {})
            .get('issueData', {})
        )
        if not issue_info:
            self.abort_recipe_processing('Unable to find issue info')

        self.cover_url = issue_info['image_url'] + '?w=800'

        edition_date = datetime.strptime(issue_info['issue_date'], '%Y-%m-%d')
        self.timefmt = f' [{edition_date:%B %Y}]'

        feeds = {}
        for section in issue_info.get('article_previews', {}):
            for article in issue_info.get('article_previews', {}).get(section, []):
                self.log('\t', article['title'])
                if section.startswith('featur'):
                    feed_name = section.capitalize()
                else:
                    feed_name = article['category']
                if feed_name not in feeds:
                    feeds[feed_name] = []
                feeds[feed_name].append(
                    {
                        'title': article['title'],
                        'url': urljoin(
                            'https://www.scientificamerican.com/article/',
                            article['slug'],
                        ),
                        'description': article['summary'],
                    }
                )
        sorted_feeds = dict(sorted(feeds.items(), key=lambda x: (not x[0].startswith('Featur'), x[0])))
        return sorted_feeds.items()
